/*
============================================================================
Name        : dd_dtable.c
Author      : Jian (raphyer@hotmail.com)
Version     :
Copyright   : GPL
Description : dd_dtable.c - source file
============================================================================
*/

/* INCLUDE FILES */
#include "dd_dtable.h"


#define __new_array_size(n)         ((n) * 2)
#define __is_exceed_size(n, s)      ((n) > ((s) / 2))
#define __check_array_index(t, i)   (((i) < (t)->array_size))
#define __array_get(t, i)           (*((t)->array_ptr + i))
#define __array_set(t, i, d)        (*((t)->array_ptr + i) = (d)) 
#define __check_hash_index(t, i)    (((i) < (t)->hash_size))
#define __hash_get(t, i)            (*((t)->hash_ptr + i))
#define __hash_set(t, i, d)         (*((t)->hash_ptr + i) = (d)) ;

#define __hash1(h,s)                (h % ((s)-2) + 1)
#define __double_hash(h, h1, s, i)  (((h) + (i) * (h1)) % (s))

#define __init_node_tmp(t, nt, k)   (t)->node_tmp->type = (nt) ; (t)->node_tmp->key = (void*)(k) 

#define __ARRAY_INIT_SIZE   20 
#define __HASH_INIT_SIZE    _hash_sizes[0]

#define __NOT_FOUND_INDEX   ((DD_UINT)-1)


#ifdef __DD_PERFORMANCE_CHECK
static DD_UINT _operator_count = 0 ;
static DD_UINT _find_count  = 0 ;

static DD_BOOL _resize_flag = DD_FALSE ;

#define __operator_count_inc()  if(!_resize_flag) _operator_count++
#define __operator_count_dec()  if(!_resize_flag) _operator_count--
#define __find_count_inc()      if(!_resize_flag) _find_count++

#define __set_resize_flag()     _resize_flag = DD_TRUE 
#define __reset_resize_flag()   _resize_flag = DD_FALSE

#define __clear_per_data()      _resize_flag = DD_FALSE ; _operator_count = 0 ; _find_count = 0 

#else
#define __operator_count_inc()  
#define __operator_count_dec()
#define __find_count_inc()      
#define __set_resize_flag()
#define __reset_resize_flag()
#define __clear_per_data()  

#endif  /* __DD_PERFORMANCE_CHECK */

static const DD_UINT _hash_sizes[] = {
    17, 37, 79, 163, 331, 673,1361,2729,
        5471,10949, 21911, 43853, 87719, 175447, 350899, 701819, 
        1403641, 2807303, 5614657, 11229331, 22458671, 44917381, 
        89834777, 179669557, 359339171, 718678369, 1437356741, 2147483647
};


typedef enum _dtable_node_type{
    ENodeDeleted,
    ENodeNumber, 
    ENodeString, 
    ENodeOther
}dtable_node_type;


typedef struct __dd_hash_node {
    dtable_node_type  type ;
    void*             key ;
    dd_dtable_value*  val ;
}dd_hash_node;


static dd_hash_node* _create_num_node(DD_UINT number, dd_dtable_value* val) 
{
    dd_hash_node* node = (dd_hash_node*)DD_MALLOC(sizeof(dd_hash_node)) ;
    node->type         = ENodeNumber ;
    node->key          = (void*)number ;
    node->val          = val ;
    return node ;
}

static dd_hash_node* _create_str_node(const DD_CHAR* str, dd_dtable_value* val) 
{
    dd_hash_node* node = (dd_hash_node*)DD_MALLOC(sizeof(dd_hash_node)) ;
    node->type         = ENodeString ;
    node->key          = DD_MALLOC(DD_STRLEN(str)+1) ;
    node->val          = val ;

    DD_STRCPY(node->key, str) ;

    return node ;
}

static dd_hash_node* _create_other_node(const dd_dtable_key* key, dd_dtable_value* val)
{
    dd_hash_node* node = (dd_hash_node*)DD_MALLOC(sizeof(dd_hash_node)) ;
    node->type         = ENodeOther ;
    node->key          = (void*)key ;
    node->val          = val ;
    return node ;
}

static void _destroy_node(dd_hash_node* node)
{
    if (node) {
        if (node->type == ENodeString)
            DD_FREE(node->key) ;

        DD_FREE(node) ;
    }
}


/* The bkdr string hash function */
static DD_UINT _str_hash(const DD_CHAR* str)
{
    DD_UINT seed = 13131; /* 31 131 1313 13131 131313 etc..*/
    DD_UINT hash = 0;

    while (*str)
        hash = hash * seed + (*str++);

    return (hash & 0x7FFFFFFF);
}

static DD_UINT _new_hash_size(DD_UINT ori_size)
{
    DD_INT i = 0 ;
    for (; i < sizeof(_hash_sizes) / sizeof(DD_UINT); i++)
    {
        if (ori_size < _hash_sizes[i]) 
            return _hash_sizes[i] ;
    }

    __DD_ASSERT(DD_FALSE) ;
    return ori_size + 100000 ;
}


static DD_UINT _node_hash(const dd_dtable* dtable, const dd_hash_node* node)
{
    __DD_ASSERT_DEFENSE(dtable && node && (node->type) > ENodeDeleted, return 0) ;

    if (node->type == ENodeNumber) {
        return (DD_UINT)node->key ;
    } else if (node->type == ENodeString) {
        return _str_hash((const DD_CHAR*)node->key) ;
    } else {
        __DD_ASSERT_DEFENSE(dtable->key_hash, return 0) ;
        return dtable->key_hash(node->key) ;
    }
}


static DD_BOOL _node_equal(const dd_dtable* dtable, const dd_hash_node* node1, const dd_hash_node* node2)
{
    if (node1->type != node2->type || node1->type <= ENodeDeleted)
        return DD_FALSE ;

    if (node1->type == ENodeString)
        return (DD_STRCMP((const DD_CHAR*)node1->key, (const DD_CHAR*)node2->key) == 0) ;

    if (node1->type == ENodeNumber)
        return ((DD_UINT)(node1->key)) == ((DD_UINT)(node2->key)) ;

    if (node1->type == ENodeOther)
        return dtable->key_equal(node1->key, node2->key) ;

    return DD_FALSE ;
}


static void _add_to_hash_part(dd_dtable* dtable, dd_hash_node* node)
{
    DD_UINT hash        = _node_hash(dtable, node);
    DD_UINT hash1       = __hash1(hash, dtable->hash_size) ;
    dd_hash_node* inode = DD_NULL ;
    DD_UINT i           = 0 ;
    DD_UINT index       = 0 ;

    while(DD_TRUE) {
        __find_count_inc() ;

        index = __double_hash(hash, hash1, dtable->hash_size, i) ;
        inode = __hash_get(dtable, index) ;

        if (!inode || inode->type == ENodeDeleted) {
            _destroy_node(inode) ;
            __hash_set(dtable, index, node) ;
            dtable->hash_count++ ;
            return;
        }

        if (_node_equal(dtable, node, inode)) {
            inode->val = node->val ;
            _destroy_node(node) ;
            return;
        } 

        i++ ;

        __DD_ASSERT_DEFENSE(i < dtable->hash_size, return) ;
    }
}

static DD_UINT _find_tmp_in_hash_part(const dd_dtable* dtable)
{
    const dd_hash_node* node = DD_NULL ;

    DD_UINT hash        = _node_hash(dtable, dtable->node_tmp);
    DD_UINT hash1       = __hash1(hash, dtable->hash_size) ;
    DD_UINT i           = 0 ;
    DD_UINT index       = 0 ;

    while(DD_TRUE) {
        __find_count_inc() ;

        index = __double_hash(hash, hash1, dtable->hash_size, i) ;
        node  = __hash_get(dtable, index) ;

        if (!node)
            break ;

        if (_node_equal(dtable, node, dtable->node_tmp))
            return index ;

        i++ ;

        __DD_ASSERT_DEFENSE(i < dtable->hash_size, return __NOT_FOUND_INDEX) ;
    } 

    return __NOT_FOUND_INDEX ;
}

static void _re_size(dd_dtable* dtable)
{
    DD_BOOL resize_array = __is_exceed_size(dtable->array_count, dtable->array_size) ;
    DD_BOOL resize_hash  = __is_exceed_size(dtable->hash_count, dtable->hash_size) ;

    __set_resize_flag() ;

    if (resize_array) {
        dd_dtable_value** pre_ptr = dtable->array_ptr ;
        DD_UINT old_size          = dtable->array_size ;
        dtable->array_size        = __new_array_size(dtable->array_size) ;
        dtable->array_ptr  = (dd_dtable_value**)DD_MALLOC(dtable->array_size * sizeof(dd_dtable_value*)) ;
        DD_MEMSET(dtable->array_ptr, 0, dtable->array_size * sizeof(dd_dtable_value*)) ;
        DD_MEMCPY(dtable->array_ptr, pre_ptr, sizeof(dd_dtable_value*) * old_size) ;
        DD_FREE(pre_ptr) ;
    } 

    if (resize_hash) {

        dd_hash_node** pre_ptr = dtable->hash_ptr ;
        DD_UINT old_size       = dtable->hash_size ;
        dd_hash_node* node = DD_NULL ;
        DD_UINT i = 0 ;

        dtable->hash_size  = _new_hash_size(dtable->hash_size) ;
        dtable->hash_count = 0 ;
        dtable->hash_ptr   = (dd_hash_node**)DD_MALLOC(dtable->hash_size * sizeof(dd_hash_node*)) ;
        DD_MEMSET(dtable->hash_ptr, 0, dtable->hash_size * sizeof(dd_hash_node*)) ;

        for(; i < old_size; i++) {

            node = (*(pre_ptr + i)) ;

            if (!node) continue ;

            if (node->type == ENodeNumber) { 

                if (__check_array_index(dtable, (DD_UINT)node->key)) {
                    __DD_ASSERT(__array_get(dtable, (DD_UINT)node->key) == DD_NULL) ;
                    __array_set(dtable, (DD_UINT)node->key, node->val) ;
                    dtable->array_count++ ;
                    node->type = ENodeDeleted ;
                }
                else {
                    _add_to_hash_part(dtable, node) ;
                }
            }
            else if (node->type == ENodeString || node->type == ENodeOther) {
                _add_to_hash_part(dtable, node) ;
            }
            else if (node->type == ENodeDeleted) {
                _destroy_node(node) ;
            }
        }
    } 
    else if (resize_array) {
        dd_hash_node* node = DD_NULL ;
        DD_UINT i = 0 ;
        for( ; i < dtable->hash_size; i++) {
            node = __hash_get(dtable, i) ;
            if (node && node->type == ENodeNumber && __check_array_index(dtable, (DD_UINT)node->key)) { 
                __array_set(dtable, (DD_UINT)node->key, node->val) ;
                dtable->array_count++ ;
                dtable->hash_count-- ;
                node->type = ENodeDeleted ;
            }
        }
    }

    __reset_resize_flag() ;
}


dd_dtable* dd_dtable_create(
                            DD_UINT array_init_size,    /* If the array_init_size = 0, the dd_dtable is work like a hash_table */
                            DD_UINT hash_init_size,     /* If the hash_init_size = 0, the dd_dtable is work like a vector */
                            DD_UINT (*key_hash)(const dd_dtable_key*),   /* Can be null, if you only use the NUMBER and STRING */
                            DD_BOOL (*key_equal)(const dd_dtable_key*, const dd_dtable_key*)	/* Can be null, if you only use the NUMBER and STRING */
                            ) 
{
    dd_dtable* dtable = (dd_dtable*)DD_MALLOC(sizeof(dd_dtable)) ;
    DD_MEMSET(dtable, 0, sizeof(dd_dtable)) ;

    if (array_init_size > 0) {
        dtable->array_size = array_init_size ;
        dtable->array_ptr  = (dd_dtable_value**)DD_MALLOC(dtable->array_size * sizeof(dd_dtable_value*)) ;
        DD_MEMSET(dtable->array_ptr, 0, dtable->array_size * sizeof(dd_dtable_value*)) ;
    }

    if (hash_init_size > 0) {
        dtable->hash_size = _new_hash_size(hash_init_size) ;
        dtable->hash_ptr  = (dd_hash_node**)DD_MALLOC(dtable->hash_size * sizeof(dd_hash_node*)) ;
        DD_MEMSET(dtable->hash_ptr, 0, dtable->hash_size * sizeof(dd_hash_node*)) ;
    }

    dtable->node_tmp  = _create_num_node(0, DD_NULL) ;
    dtable->key_hash  = key_hash ;
    dtable->key_equal = key_equal ;

    return dtable ;
}

void dd_dtable_destroy(dd_dtable* dtable) 
{
    __DD_ASSERT_DEFENSE(dtable, return) ;

    if (dtable->array_ptr)
        DD_FREE(dtable->array_ptr) ;

    if (dtable->hash_ptr)
        DD_FREE(dtable->hash_ptr) ;

    DD_FREE(dtable->node_tmp) ;
    DD_FREE(dtable) ;
}


DD_BOOL dd_dtable_set_num(dd_dtable* dtable, DD_UINT number, dd_dtable_value* value) 
{
    __DD_ASSERT_DEFENSE(dtable, return DD_FALSE) ;

    __operator_count_inc() ;

    if (!dtable->array_ptr) {
        dtable->array_size = __ARRAY_INIT_SIZE ;
        dtable->array_ptr  = (dd_dtable_value**)DD_MALLOC(dtable->array_size * sizeof(dd_dtable_value*)) ;
        DD_MEMSET(dtable->array_ptr, 0, dtable->array_size * sizeof(dd_dtable_value*)) ;
    }

    if (__check_array_index(dtable, number)) {
        if (__array_get(dtable, number) != DD_NULL) {
            __array_set(dtable, number, value) ;
        }
        else {
            __array_set(dtable, number, value) ;
            dtable->array_count++ ;
        }
        __operator_count_dec() ;    /* NOT COUNT ARRAY PART */
    }
    else {
        _add_to_hash_part(dtable, _create_num_node(number, value)) ;
    }

    _re_size(dtable) ;

    return DD_TRUE ;
}


dd_dtable_value* dd_dtable_get_num(const dd_dtable* dtable, DD_UINT number) 
{
    __DD_ASSERT_DEFENSE(dtable && dtable->array_ptr, return DD_NULL) ;

    __operator_count_inc() ;

    if (__check_array_index(dtable, number)) {
        __operator_count_dec() ;    /* NOT COUNT ARRAY PART */
        return __array_get(dtable, number) ;
    }
    else {
        DD_UINT index = __NOT_FOUND_INDEX ;
        __init_node_tmp(dtable, ENodeNumber, number) ;
        index = _find_tmp_in_hash_part(dtable) ;
        if (index != __NOT_FOUND_INDEX)
            return __hash_get(dtable, index)->val ;
    }

    return DD_NULL ;
}

dd_dtable_value* dd_dtable_delete_num(dd_dtable* dtable, DD_UINT number) 
{
    dd_dtable_value* val = DD_NULL ;

    __DD_ASSERT_DEFENSE(dtable && dtable->array_ptr, return DD_NULL) ;

    __operator_count_inc() ;

    if (__check_array_index(dtable, number)) {
        val = __array_get(dtable, number) ;
        __array_set(dtable, number, DD_NULL) ;
        dtable->array_count-- ;

        __operator_count_dec() ;    /* NOT COUNT ARRAY PART */
    }
    else {
        DD_UINT index = __NOT_FOUND_INDEX ;
        __init_node_tmp(dtable, ENodeNumber, number) ;
        index = _find_tmp_in_hash_part(dtable) ;
        if (index != __NOT_FOUND_INDEX) {
            val = __hash_get(dtable, index)->val ;
            __hash_get(dtable, index)->type = ENodeDeleted ;
            dtable->hash_count-- ;
        }
    }

    __DD_ASSERT(val) ;

    return val ;
}

void dd_dtable_set_str(dd_dtable* dtable, const DD_CHAR* str, dd_dtable_value* value) 
{
    __DD_ASSERT_DEFENSE(dtable && str, return) ;

    __operator_count_inc() ;

    if (!dtable->hash_ptr) {
        dtable->hash_size = __HASH_INIT_SIZE ;
        dtable->hash_ptr  = (dd_hash_node**)DD_MALLOC(dtable->hash_size * sizeof(dd_hash_node*)) ;
        DD_MEMSET(dtable->hash_ptr, 0, dtable->hash_size * sizeof(dd_hash_node*)) ;
    }

    _add_to_hash_part(dtable, _create_str_node(str, value)) ;

    _re_size(dtable) ;
}

dd_dtable_value* dd_dtable_get_str(const dd_dtable* dtable, const DD_CHAR* str) 
{
    DD_INT index         = __NOT_FOUND_INDEX ;

    __DD_ASSERT_DEFENSE(dtable && dtable->hash_ptr && str, return DD_NULL) ;

    __operator_count_inc() ;

    __init_node_tmp(dtable, ENodeString, str) ;

    index = _find_tmp_in_hash_part(dtable) ;

    if (index != __NOT_FOUND_INDEX)
        return __hash_get(dtable, index)->val ;

    return DD_NULL ;
}

dd_dtable_value* dd_dtable_delete_str(dd_dtable* dtable, const DD_CHAR* str) 
{
    DD_INT index         = 0 ;

    __DD_ASSERT_DEFENSE(dtable && dtable->hash_ptr && str, return DD_NULL) ;

    __operator_count_inc() ;

    __init_node_tmp(dtable, ENodeString, str) ;

    index = _find_tmp_in_hash_part(dtable) ;

    if (index != __NOT_FOUND_INDEX) {
        dd_dtable_value* val = __hash_get(dtable, index)->val ;
        __hash_get(dtable, index)->type = ENodeDeleted ;
        dtable->hash_count-- ;
        return val ;
    }

    return DD_NULL ;
}

void dd_dtable_set_key(dd_dtable* dtable, const dd_dtable_key* key, dd_dtable_value* value) 
{
    __DD_ASSERT_DEFENSE(dtable && dtable->key_hash && dtable->key_equal, return) ;

    __operator_count_inc() ;

    if (!dtable->hash_ptr) {
        dtable->hash_size = __HASH_INIT_SIZE ;
        dtable->hash_ptr  = (dd_hash_node**)DD_MALLOC(dtable->hash_size * sizeof(dd_hash_node*)) ;
        DD_MEMSET(dtable->hash_ptr, 0, dtable->hash_size * sizeof(dd_hash_node*)) ;
    }

    _add_to_hash_part(dtable, _create_other_node(key, value)) ;

    _re_size(dtable) ;
}

dd_dtable_value* dd_dtable_get_key(const dd_dtable* dtable, const dd_dtable_key* key) 
{
    DD_INT index         = __NOT_FOUND_INDEX ;

    __DD_ASSERT_DEFENSE(dtable && dtable->key_hash && dtable->key_equal, return DD_NULL) ;

    __operator_count_inc() ;

    __init_node_tmp(dtable, ENodeOther, key) ;

    index = _find_tmp_in_hash_part(dtable) ;

    if (index != __NOT_FOUND_INDEX)
        return __hash_get(dtable, index)->val ;

    return DD_NULL ;
}

dd_dtable_value* dd_dtable_delete_key(dd_dtable* dtable, const dd_dtable_key* key) 
{
    DD_INT index         = 0 ;

    __DD_ASSERT_DEFENSE(dtable && dtable->key_hash && dtable->key_equal, return DD_NULL) ;

    __operator_count_inc() ;

    __init_node_tmp(dtable, ENodeOther, key) ;

    index = _find_tmp_in_hash_part(dtable) ;

    if (index != __NOT_FOUND_INDEX) {
        dd_dtable_value* val = __hash_get(dtable, index)->val ;
        __hash_get(dtable, index)->type = ENodeDeleted ;
        dtable->hash_count-- ;
        return val ;
    }

    return DD_NULL ;
}


#ifdef __DD_UNITTEST

#include "dd_vector.h"
#include "dd_test.h"

typedef struct __ut_test_key_pair {
    dtable_node_type  type ;
    void* key ;
    void* value ;

}ut_test_key_pair;

DD_CHAR* _random_str()
{
    DD_UINT i = 0 ;
    DD_UINT count = DD_RAND() % 15 + 1 ;
    DD_CHAR* str = DD_MALLOC(count + 1) ;

    while(i < count) {
        str[i] = DD_RAND() % 26 + 'a' ;
        i++ ;
    }
    str[count] = 0 ;
    return str ;
}


static DD_UINT _ut_key_hash(const dd_dtable_key* key) 
{
    return (DD_UINT)key ;
}


static DD_BOOL _ut_key_equal(const dd_dtable_key* key1, const dd_dtable_key* key2) 
{
    return (DD_UINT)key1 == (DD_UINT)key2 ;
}

ut_test_key_pair* _ut_create_key_pair_random()
{
    ut_test_key_pair* data = (ut_test_key_pair*)DD_MALLOC(sizeof(ut_test_key_pair)) ;

    data->type  = (dtable_node_type)(DD_RAND() % 3 + ENodeNumber);
    data->value = (void*)DD_RAND() ;
    if ((DD_INT)data->value == 0) data->value = (void*)1 ;

    if (data->type == ENodeNumber) {
        data->key = (void*)DD_RAND() ;
    }
    else if (data->type == ENodeString) {
        data->key = (void*)_random_str();
    }
    else if (data->type == ENodeOther) {
        data->key = (void*)DD_RAND() ;
    }   
    else 
        __DD_ASSERT(DD_FALSE) ;

    return data ;
}

ut_test_key_pair* _ut_create_key_pair(DD_INT i)
{
    ut_test_key_pair* data = (ut_test_key_pair*)DD_MALLOC(sizeof(ut_test_key_pair)) ;

    data->type  = ENodeNumber;
    data->value = (void*)(i+1);
    data->key   = (void*)(i+1) ;

    return data ;
}


void _ut_destroy_key_pair(ut_test_key_pair* data)
{
    if (data->type == ENodeString)
        DD_FREE(data->key) ;
    DD_FREE(data) ;
}

DD_INT _ut_pair_compare(const void* key1, const void* key2)
{
    ut_test_key_pair* data1 = (ut_test_key_pair*)key1 ;
    ut_test_key_pair* data2 = (ut_test_key_pair*)key2 ;

    if (data1->type == data2->type) {
        if (data1->type == ENodeString)
            return DD_STRCMP((const DD_CHAR*)data1->key, (const DD_CHAR*)data2->key) ;

        if (data1->type == ENodeNumber || data1->type == ENodeOther) {
            DD_INT val1 = (DD_INT)data1->key ;
            DD_INT val2 = (DD_INT)data2->key ;

            if (val1 == val2)  return 0 ;

            if (val1 < val2)  return -1 ;

            return 1 ;
        }
        __DD_ASSERT_DEFENSE(DD_FALSE, return -1) ;
    }

    {
        if (data1->type < data2->type)  return -1 ;

        return 1 ;  
    }
}


#define __TEST_TIMES            (100000 + 1)


DD_BOOL dd_dtable_test() 
{
    dd_dtable* test_dtable = dd_dtable_create(19, 19, _ut_key_hash, _ut_key_equal) ;
    dd_vector* test_vec = dd_vector_create(__TEST_TIMES) ;

    DD_INT i = 0 ;
    DD_INT count = 0 ;

    DD_SRAND((DD_UINT)DD_TIME(0)) ;

    i = 0 ;
    for (; i < __TEST_TIMES; i++) {
        ut_test_key_pair* data = DD_NULL ;
        /*
        if ( i < (__TEST_TIMES * 2) / 5)
        data = _ut_create_key_pair(i) ;
        else
        */
        data = _ut_create_key_pair_random();

        if (dd_vector_find_by_key(test_vec, data, _ut_pair_compare) == -1)
            dd_vector_insert_by(test_vec, data, _ut_pair_compare) ;
    }

    dd_ut_time_start("dd_dtable counter") ;

    __clear_per_data() ;

    i = 0 ;
    for (; i < dd_vector_count(test_vec); i++){
        ut_test_key_pair* data = (ut_test_key_pair*)dd_vector_get(test_vec, i) ;

        if (data->type == ENodeNumber) {
            dd_dtable_set_num(test_dtable, (DD_UINT)data->key, data->value) ;
        }
        else if (data->type == ENodeString) {
            dd_dtable_set_str(test_dtable, (DD_CHAR*)data->key, data->value) ;
        }
        else if (data->type == ENodeOther) {
            dd_dtable_set_key(test_dtable, data->key, data->value) ;
        }
    }

    dd_ut_time_end("dd_dtable counter: After the SET") ;

    DD_LOG("dd_dtable_test dtable array size = %d array count = %d hash_size = %d hash count = %d", 
        test_dtable->array_size, test_dtable->array_count, test_dtable->hash_size, test_dtable->hash_count) ;

    if (dd_vector_count(test_vec) != (DD_INT)(test_dtable->hash_count + test_dtable->array_count)) {
        DD_LOG("dd_dtable_test SET COUNT ERROR") ;
        return DD_FALSE;
    }

    DD_LOG("dd_dtable_test performance dump hash part operator = %d find = %d and find/operator = %f", 
        _operator_count, _find_count, _operator_count > 0 ? (DD_DOUBLE)_find_count / _operator_count : 0) ;

    __clear_per_data() ;

    i = 0 ;
    for (; i < dd_vector_count(test_vec); i++){

        ut_test_key_pair* data = (ut_test_key_pair*)dd_vector_get(test_vec, i) ;

        if (data->type == ENodeNumber) {
            dd_dtable_value* val = dd_dtable_get_num(test_dtable, (DD_UINT)data->key) ;
            if (!val || val != data->value) {
                DD_LOG("dd_dtable_get_num ERROR") ;
                return DD_FALSE ;
            }

        }
        else if (data->type == ENodeString) {
            dd_dtable_value* val = dd_dtable_get_str(test_dtable, (const DD_CHAR*)data->key) ;
            if (!val || val != data->value) {
                DD_LOG("dd_dtable_get_str ERROR") ;
                return DD_FALSE ;
            }
        }
        else if (data->type == ENodeOther) {
            dd_dtable_value* val = dd_dtable_get_key(test_dtable, data->key) ;
            if (!val || val != data->value) {
                DD_LOG("dd_dtable_get_key ERROR") ;
                return DD_FALSE ;
            }
        }
    }

    dd_ut_time_end("dd_dtable counter: After the GET") ;

    DD_LOG("dd_dtable_test performance dump hash part operator = %d find = %d and find/operator = %f", 
        _operator_count, _find_count, _operator_count > 0 ? (DD_DOUBLE)_find_count / _operator_count : 0) ;

    __clear_per_data() ;

    i = 0 ;
    count = dd_vector_count(test_vec) ;

    for (; i < count; i++) {
        ut_test_key_pair* data = (ut_test_key_pair*)dd_vector_delete_by_index(test_vec, dd_vector_count(test_vec) - 1) ;

        if (data->type == ENodeNumber) {
            dd_dtable_value* val = dd_dtable_delete_num(test_dtable, (DD_UINT)data->key) ;
            if (!val || val != data->value) {
                DD_LOG("dd_dtable_delete_num ERROR") ;
                return DD_FALSE ;
            }

        }
        else if (data->type == ENodeString) {
            dd_dtable_value* val = dd_dtable_delete_str(test_dtable, (const DD_CHAR*)data->key) ;
            if (!val || val != data->value) {
                DD_LOG("dd_dtable_delete_str ERROR") ;
                return DD_FALSE ;
            }
        }
        else if (data->type == ENodeOther) {
            dd_dtable_value* val = dd_dtable_delete_key(test_dtable, data->key) ;
            if (!val || val != data->value) {
                DD_LOG("dd_dtable_delete_key ERROR") ;
                return DD_FALSE ;
            }
        }
    }

    if ((test_dtable->hash_count + test_dtable->array_count) != 0 ) {
        DD_LOG("dd_dtable_test DELETE COUNT ERROR") ;
        return DD_FALSE;
    }

    dd_ut_time_end("dd_dtable counter: After the DELETE") ;

    DD_LOG("dd_dtable_test performance dump hash part operator = %d find = %d and find/operator = %f", 
        _operator_count, _find_count, _operator_count > 0 ? (DD_DOUBLE)_find_count / _operator_count : 0) ;

    return DD_TRUE ;
}

#endif	/* __DD_UNITTEST */


/* End of File */
